import { expect, test } from 'vitest'

import { computeStatistics } from '../src/utils'
import { toSortedSamples } from './utils'

test('computeStatistics', () => {
  let stats = computeStatistics(toSortedSamples([1, 2, 3, 4, 5, 6]))
  expect(stats.min, 'min').toBe(1)
  expect(stats.max, 'max').toBe(6)
  expect(stats.df, 'df').toBe(5)
  expect(stats.critical, 'critical').toBe(2.57058183661474)
  expect(stats.mean, 'mean').toBe(3.5)
  expect(stats.variance, 'variance').toBe(3.5)
  expect(stats.sd, 'sd').toBe(1.8708286933869707)
  expect(stats.sem, 'sem').toBe(0.7637626158259734)
  expect(stats.moe, 'moe').toBe(1.9633143077276087)
  expect(stats.rme, 'rme').toBe((stats.moe / stats.mean) * 100)
  expect(stats.p50, 'p50').toBe(3.5)
  expect(stats.p75, 'p75').toBe(4.75)
  expect(stats.p99, 'p99').toBe(5.95)
  expect(stats.p995, 'p995').toBe(5.975)
  expect(stats.p999, 'p999').toBe(5.995)
  expect(stats.mad, 'mad').toBe(1.5)
  expect(stats.aad, 'aad').toBe(1.5)
  stats = computeStatistics(toSortedSamples([1, 2, 3, 4, 5, 6, 7]))
  expect(stats.min, 'min').toBe(1)
  expect(stats.max, 'max').toBe(7)
  expect(stats.df, 'df').toBe(6)
  expect(stats.critical, 'critical').toBe(2.446911848791681)
  expect(stats.mean, 'mean').toBe(4)
  expect(stats.variance, 'variance').toBe(4.666666666666667)
  expect(stats.sd, 'sd').toBe(2.160246899469287)
  expect(stats.sem, 'sem').toBe(0.816496580927726)
  expect(stats.moe, 'moe').toBe(1.9978951583699485)
  expect(stats.rme, 'rme').toBe((stats.moe / stats.mean) * 100)
  expect(stats.p50, 'p50').toBe(4)
  expect(stats.p75, 'p75').toBe(5.5)
  expect(stats.p99, 'p99').toBe(6.9399999999999995)
  expect(stats.p995, 'p995').toBe(6.97)
  expect(stats.p999, 'p999').toBe(6.994)
  expect(stats.mad, 'mad').toBe(2)
  expect(stats.aad, 'aad').toBe(1.7142857142857142)
})

test('computeStatistics - sample [0]', () => {
  const stats = computeStatistics(toSortedSamples([0]))
  expect(stats.min, 'min').toBe(0)
  expect(stats.max, 'max').toBe(0)
  expect(stats.df, 'df').toBe(0)
  expect(stats.critical, 'critical').toBe(12.706204736432102)
  expect(stats.mean, 'mean').toBe(0)
  expect(stats.variance, 'variance').toBe(0)
  expect(stats.sd, 'sd').toBe(0)
  expect(stats.sem, 'sem').toBe(0)
  expect(stats.moe, 'moe').toBe(0)
  expect(stats.rme, 'rme').toBe(Number.POSITIVE_INFINITY)
  expect(stats.p50, 'p50').toBe(0)
  expect(stats.p75, 'p75').toBe(0)
  expect(stats.p99, 'p99').toBe(0)
  expect(stats.p995, 'p995').toBe(0)
  expect(stats.p999, 'p999').toBe(0)
  expect(stats.mad, 'mad').toBe(0)
  expect(stats.aad, 'aad').toBe(0)
})

test('computeStatistics - big sample [0, 0, ...]', () => {
  const stats = computeStatistics(
    toSortedSamples([0, ...new Array<number>(1999).fill(0)])
  )
  expect(stats.min, 'min').toBe(0)
  expect(stats.max, 'max').toBe(0)
  expect(stats.df, 'df').toBe(1999)
  expect(stats.critical, 'critical').toBe(1.96)
  expect(stats.mean, 'mean').toBe(0)
  expect(stats.variance, 'variance').toBe(0)
  expect(stats.sd, 'sd').toBe(0)
  expect(stats.sem, 'sem').toBe(0)
  expect(stats.moe, 'moe').toBe(0)
  expect(stats.rme, 'rme').toBe(Number.POSITIVE_INFINITY)
  expect(stats.p50, 'p50').toBe(0)
  expect(stats.p75, 'p75').toBe(0)
  expect(stats.p99, 'p99').toBe(0)
  expect(stats.p995, 'p995').toBe(0)
  expect(stats.p999, 'p999').toBe(0)
  expect(stats.mad, 'mad').toBe(0)
  expect(stats.aad, 'aad').toBe(0)
})

test('computeStatistics - big sample [0, 1, 2, 3, ...(n+1)[]]', () => {
  const stats = computeStatistics(
    toSortedSamples([
      0,
      ...new Array<number>(1999).fill(0).map((_, i) => i + 1),
    ])
  )
  expect(stats.min, 'min').toBe(0)
  expect(stats.max, 'max').toBe(1999)
  expect(stats.df, 'df').toBe(1999)
  expect(stats.critical, 'critical').toBe(1.96)
  expect(stats.mean, 'mean').toBe(999.5)
  expect(stats.variance, 'variance').toBe(333500)
  expect(stats.sd, 'sd').toBe(577.4945887192364)
  expect(stats.sem, 'sem').toBe(12.913171570144957)
  expect(stats.moe, 'moe').toBe(25.309816277484117)
  expect(stats.rme, 'rme').toBe(2.532247751624224)
  expect(stats.p50, 'p50').toBeCloseTo(999.5)
  expect(stats.p75, 'p75').toBeCloseTo(1499.25)
  expect(stats.p99, 'p99').toBeCloseTo(1979.01)
  expect(stats.p995, 'p995').toBeCloseTo(1989)
  expect(stats.p999, 'p999').toBeCloseTo(1997)
  expect(stats.mad, 'mad').toBe(500)
  expect(stats.aad, 'aad').toBeCloseTo(500)
})
